package main

import (
	"errors"
	"fmt"
	"iot-base/common/notify"
	"strconv"
	"time"

	"iot-base/common/modbus"

	"iot-base/common/cache"
	"iot-base/devc/common/loader"
	"sync"
)

//modbus配置参数
//type Modbusconfig struct {
//	Name   string
//	Type   string
//	Serial SerialOption
//	Net    NetOption
//}

//串口配置参数
type SerialOption struct {
	Name     string
	BaudRate int
	DataBits int
	Parity   string
	StopBits int
}

//tcp配置参数
type NetOption struct {
	IP   string
	Port string
}

//物模型相关配置
type ThingCon struct {
	Conf         byte //功能码
	Slave        byte //从站地址
	AddressStart byte //起始地址
	quantity     byte //读取长度
}

//连接对应设备id关系
type Connect struct {
	id       string
	protocol *loader.Protocol
}

//当前存储的modbus连接客户端的状态使用
type ConnectStatus struct {
	IsConnected bool
	Client      modbus.Client
}
type Order struct {
	Code   string
	Begin  uint16
	Count  uint16
	Value  []byte
	Client modbus.Client
	Style  string
}

type OrderRet struct {
	Vlue []byte
	Err  error
}

//var db *gorm.DB //数据库连接 //用于定义modbus配置参数
var ProtocolConnect chan Connect //用于定义协议连接及设备id映射关系
//var Connected map[string]ConnectStatus                                                                                                  //用于确认设备连接是否已连接
var PropertyEncodeFun map[string]func(string, loader.Param) []byte                                                                      //用于存储编码调用函数使用
var PropertyDecodeFun map[string]func([]byte, loader.Param) interface{}                                                                 //用于存储解码调用函数使用
var WriteFun map[string]func(cmd loader.ServiceCmd, param map[string]interface{}, client modbus.Client) (map[string]interface{}, error) //用于存储特殊处理的服务函数
var OrderChan chan Order                                                                                                                //用于发送单个命令通道
var OrderReturn chan OrderRet

func init() {
	ProtocolConnect = make(chan Connect, 30)
	OrderChan = make(chan Order)
	OrderReturn = make(chan OrderRet)
	//	Connected = map[string]ConnectStatus{}
	PropertyDecodeFun = map[string]func([]byte, loader.Param) interface{}{
		"int8h":   ByteToHInt8,
		"int8l":   ByteToLInt8,
		"int16":   ByteToInt16,
		"int32":   ByteToInt32,
		"int64":   ByteToInt64,
		"float32": ByteToFloat32,
		"Double":  ByteToDouble,
		"uint16":  ByteToUint16,
		"uint32":  ByteToUint32,
		"uint64":  ByteToUint64,
		"YLog":    YLog,
		"string":  ByteToString,
		"bool":    ByteToBool,
		"bcd_gps": ByteTogps,
	}
	PropertyEncodeFun = map[string]func(string, loader.Param) []byte{
		"int16":   Int16ToByte,
		"int32":   Int32ToByte,
		"int64":   Int64ToByte,
		"float32": Float32ToByte,
		"Double":  DoubleToByte,
		"uint16":  Uint16ToByte,
		"uint32":  Uint32ToByte,
		"uint64":  Uint64ToByte,
		"string":  StringToByte,
		"bool":    BoolToByte,
	}
	WriteFun = map[string]func(cmd loader.ServiceCmd, param map[string]interface{}, client modbus.Client) (map[string]interface{}, error){
		"m_tLcsjBdvEy1og2tn2PkTx.delay_control": ControlDelay,
	}
	//db,err := dbconn.ConnectDB()
	//if err!=nil{
	//	fmt.Println("db conn err:",err)
	//}
	//fmt.Println("db conn success:",db)
}

func main() {
	loader.SetParamEx(false, "modbus", 10, GetTask)
	go process()
	time.Sleep(1 * time.Second)
	go Serve()
	//go GetResSv()
	wg := sync.WaitGroup{}
	wg.Add(1)
	wg.Wait()
}

//用于获取属性上报的任务
func GetTask(id string, thing *cache.ThingInfo, v interface{}, round int64) (interface{}, error) {
	//获取解析协议
	protocol, err := loader.GetProtocolParam(thing.Thing.UID)
	fmt.Println("get task!")
	if err != nil {
		fmt.Println("get protocol err:", err)
		return nil, errors.New("get protocol err!")
	}
	ProtocolConnect <- Connect{id, protocol}
	return nil, nil
}

func process() {
	for {
		//此处循环提取任务
		fmt.Println("run process")
		prot := <-ProtocolConnect
		fmt.Println("prot:", prot)
		fmt.Println("task in")
		id := prot.id
		protocol := prot.protocol
		//获取modbus连接,根据map记录查看是否重新建立连接
		var client modbus.Client
		client = GetClient(protocol)
		//_, ok := Connected[id]
		//if !ok {
		//	client = GetClient(protocol)
		//	if client == nil {
		//		continue
		//	}
		//	Connected[id] = ConnectStatus{true, client}
		//} else {
		//	client = Connected[id].Client
		//}
		if client == nil {
			fmt.Println("Creat modbus client err!")
			//return nil,errors.New("Creat modbus client err!")
		}
		//client.SlaveID = 1
		//处理上报属性
		ParsePost(id, protocol.PropertyScans, client)
	}
}

//根据配置读取结果并按照属性参数解析
func ParsePost(id string, property []loader.PropertyScan, client modbus.Client) {
	for _, v := range property {
		tmp, _ := strconv.ParseInt(v.ScanCmd.Code, 16, 16)
		if tmp > 4 {
			continue
		}
		//存储起始寄存器
		BeginAddr := v.ScanCmd.Begin
		//此处根据配置读取结果
		result, err := GetResultEx(v.ScanCmd.Code, v.ScanCmd.Begin, v.ScanCmd.Count, nil, client, "scan")
		//result, err := GetRes(v.ScanCmd.Code, v.ScanCmd.Begin, v.ScanCmd.Count, nil, client, "scan")
		fmt.Println("result:", result)
		if err != nil || result == nil {
			fmt.Println("get result err:", err)
			continue
		}
		//count 变量属于寄存器读取数量，每个寄存器为两个字节长度
		now := time.Now().Unix()
		for _, value := range v.PropertyExplains {
			left := (value.ModbusParam.Begin - BeginAddr) * 2
			right := left + (value.ModbusParam.Count * 2)
			if int(right) > len(result) && value.ModbusParam.Func != "bool" {
				continue
			}
			if value.ModbusParam.Func == "bool" {
				right = left + value.ModbusParam.Count
			}
			//if value.PID=="IO status"{
			//	fmt.Printf("offset property:id:%s,pid:%s,sid:%s,index:%v\n",id, value.PID, value.SubID, value.Index)
			//	fmt.Println("size,offset:",value.ModbusParam.Size,value.ModbusParam.IndexOffset)
			//}
			//fmt.Println("param:----------------", value.ModbusParam.Size, value.ModbusParam.IndexOffset, value.PID, value.SubID)
			if value.ModbusParam.Size != nil && value.ModbusParam.IndexOffset != nil {
				size := *value.ModbusParam.Size
				if size > 0 {
					begin := 0
					if value.ModbusParam.BeginPos != nil {
						begin = *value.ModbusParam.BeginPos
					}
					for i := 0; i < size-begin; i++ {
						left := (value.ModbusParam.Begin - BeginAddr + uint16(*value.ModbusParam.IndexOffset*i)) * 2
						right := left + (value.ModbusParam.Count * 2)
						if value.ModbusParam.Func == "bool" {
							right = left + value.ModbusParam.Count
						}
						res := ReadFuncProxy(value.ModbusParam, result[int(left):int(right)])
						//if value.PID == "power" && (value.SubID == "key1"||value.SubID == "key2"||value.SubID == "key3") && value.Index == 0{
						//	fmt.Printf("offset property:id:%s,pid:%s,sid:%s,index:%v,v:%v\n", id, value.PID, value.SubID, value.Index+i+begin, res)
						//}
						notify.RawData(id, value.PID, value.SubID, value.Index+i+begin, res, now, now)
					}
				} else {
					//fmt.Println("left,right:",left,right,"    ",result[int(left):int(right)],"  ",result)
					res := ReadFuncProxy(value.ModbusParam, result[int(left):int(right)])
					//if value.PID == "power" && (value.SubID == "key1"||value.SubID == "key2"||value.SubID == "key3") && value.Index == 0{
					//	fmt.Printf("offset property:id:%s,pid:%s,sid:%s,index:%v,v:%v\n", id, value.PID, value.SubID, value.Index, res)
					//}

					//if value.PID=="IO status" && (value.SubID == "lock_run"){
					//	fmt.Printf("offset property:id:%s,pid:%s,sid:%s,index:%v,v:%v\n",id, value.PID, value.SubID, value.Index, res)
					//	if value.ModbusParam.Number!=nil{
					//		fmt.Println("number:",*value.ModbusParam.Number)
					//	}
					//}
					//fmt.Printf("property:id:%s,pid:%s,sid:%s,index:%v,v:%v\n",id, value.PID, value.SubID, value.Index, res)
					if res != nil {
						notify.RawData(id, value.PID, value.SubID, value.Index, res, now, now)
					}
				}
			} else {
				//fmt.Println("size:", *value.ModbusParam.Size, "offset:", *value.ModbusParam.IndexOffset)
				//此处解析单个属性使用的解析函数并上报
				//fmt.Println("left,right:",left,right,"    ",result[int(left):int(right)],"  ",result)
				res := ReadFuncProxy(value.ModbusParam, result[int(left):int(right)])
				if value.PID == "fan_status" || value.PID == "cooling_alarm" || value.PID == "condenser_temperature_sensor_error" {
					fmt.Printf("offset property:id:%s,pid:%s,sid:%s,index:%v,v:%v\n", id, value.PID, value.SubID, value.Index, res)
				}
				//if value.PID=="IO status"{
				//	fmt.Printf("offset property:id:%s,pid:%s,sid:%s,index:%v,v:%v\n",id, value.PID, value.SubID, value.Index, res)
				//	fmt.Println("size,offset:",value.ModbusParam.Size,value.ModbusParam.IndexOffset)
				//}
				//fmt.Printf("property:id:%s,pid:%s,sid:%s,index:%v,v:%v\n",id, value.PID, value.SubID, value.Index, res)
				if res != nil {
					notify.RawData(id, value.PID, value.SubID, value.Index, res, now, now)
				}
			}
		}
	}
}

func GetResSv() {
	for {
		order := <-OrderChan
		res, err := GetResultEx(order.Code, order.Begin, order.Count, order.Value, order.Client, order.Style)
		OrderReturn <- OrderRet{res, err}
	}
}

func GetRes(Code string, Begin uint16, Count uint16, Value []byte, client modbus.Client, style string) ([]byte, error) {
	OrderChan <- Order{Code, Begin, Count, Value, client, style}
	res := <-OrderReturn
	return res.Vlue, res.Err
}

//根据功能码进行调用modbus读取函数
func GetResult(Code string, Begin uint16, Count uint16, Value []byte, client modbus.Client) ([]byte, error) {
	switch Code {
	case "1":
		result, err := client.ReadCoils(Begin, Count)
		if err != nil {
			fmt.Println("read coils err:", err)
			return nil, errors.New("read coils err:" + err.Error())
		}
		return result, nil
	case "2":
		result, err := client.ReadDiscreteInputs(Begin, Count)
		if err != nil {
			fmt.Println("read DiscreteInputs err:", err)
			return nil, errors.New("read DiscreteInputs err:" + err.Error())
		}
		return result, nil
	case "3":
		result, err := client.ReadHoldingRegisters(Begin, Count)
		if err != nil {
			fmt.Println("read HoldingRegisters err:", err)
			return nil, errors.New("read HoldingRegisters err:" + err.Error())
		}
		return result, nil
	case "4":
		result, err := client.ReadInputRegisters(Begin, Count)
		if err != nil {
			fmt.Println("read InputRegisters err:", err)
			return nil, errors.New("read InputRegisters err:" + err.Error())
		}
		return result, nil
	case "5":
		result, err := client.WriteSingleCoil(Begin, Count)
		if err != nil {
			fmt.Println("Write coils err:", err)
			return nil, errors.New("Write coils err:" + err.Error())
		}
		return result, nil
	case "6":
		result, err := client.WriteSingleRegister(Begin, Count)
		if err != nil {
			fmt.Println("Write Single Register err:", err)
			return nil, errors.New("Write Single Register err:" + err.Error())
		}
		return result, nil
	case "15":
		result, err := client.WriteMultipleCoils(Begin, Count, Value)
		if err != nil {
			fmt.Println("Write Multiple Coils:", err)
			return nil, errors.New("Write Multiple Coils:" + err.Error())
		}
		return result, nil
	case "16":
		result, err := client.WriteMultipleRegisters(Begin, Count, Value)
		if err != nil {
			fmt.Println("Write Multiple Registers err:", err)
			return nil, errors.New("Write Multiple Registers err:" + err.Error())
		}
		return result, nil
	default:
		fmt.Println("no this Code")
		return nil, errors.New("no this Code")
	}
}

func GetResultEx(Code string, Begin uint16, Count uint16, Value []byte, client modbus.Client, style string) ([]byte, error) {
	switch Code {
	case "1":
		result, err := client.ReadCoilsEx(Begin, Count, style)
		if err != nil {
			fmt.Println("read coils err:", err)
			return nil, errors.New("read coils err:" + err.Error())
		}
		return result, nil
	case "2":
		result, err := client.ReadDiscreteInputsEx(Begin, Count, style)
		if err != nil {
			fmt.Println("read DiscreteInputs err:", err)
			return nil, errors.New("read DiscreteInputs err:" + err.Error())
		}
		return result, nil
	case "3":
		result, err := client.ReadHoldingRegistersEx(Begin, Count, style)
		if err != nil {
			fmt.Println("read HoldingRegisters err:", err)
			return nil, errors.New("read HoldingRegisters err:" + err.Error())
		}
		return result, nil
	case "4":
		result, err := client.ReadInputRegistersEx(Begin, Count, style)
		if err != nil {
			fmt.Println("read InputRegisters err:", err)
			return nil, errors.New("read InputRegisters err:" + err.Error())
		}
		return result, nil
	case "5":
		result, err := client.WriteSingleCoilEx(Begin, Count, style)
		if err != nil {
			fmt.Println("Write coils err:", err)
			return nil, errors.New("Write coils err:" + err.Error())
		}
		return result, nil
	case "6":
		result, err := client.WriteSingleRegisterEx(Begin, Count, style)
		if err != nil {
			fmt.Println("Write Single Register err:", err)
			return nil, errors.New("Write Single Register err:" + err.Error())
		}
		return result, nil
	case "15":
		result, err := client.WriteMultipleCoilsEx(Begin, Count, Value, style)
		if err != nil {
			fmt.Println("Write Multiple Coils:", err)
			return nil, errors.New("Write Multiple Coils:" + err.Error())
		}
		return result, nil
	case "16":
		result, err := client.WriteMultipleRegistersEx(Begin, Count, Value, style)
		if err != nil {
			fmt.Println("Write Multiple Registers err:", err)
			return nil, errors.New("Write Multiple Registers err:" + err.Error())
		}
		return result, nil
	default:
		fmt.Println("no this Code")
		return nil, errors.New("no this Code")
	}
}
